package com.sitech.ibnms.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.SQLException;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.ibatis.sqlmap.engine.scope.StatementScope;
import com.sitech.dao.BaseDao;
import com.sitech.portal.system.domain.TblSYS_LOGINMSG;

public class BaseIbnmsDao extends BaseDao {

    private static final Log log = LogFactory.getLog(BaseIbnmsDao.class);
    private SqlMapClientImpl sqlMapClient;
    private JdbcTemplate jdbcTemplate;
    protected TblSYS_LOGINMSG currentUser;

    @Resource(name = "sqlMapClient")
    public final void setSqlMapClientImpl(SqlMapClientImpl sqlMapClient) {
        this.sqlMapClient = sqlMapClient;
        this.jdbcTemplate = new JdbcTemplate(sqlMapClient.getDataSource(), true);
    }

    @Resource(name = "currentUser")
    public void setCurrentUser(TblSYS_LOGINMSG currentUser) {
        this.currentUser = currentUser;
    }

    /**
     * 附带权限过滤的查询
     *
     * <p>为SQL添加权限过滤（通过RID字段过滤），如果当前用户为admin时，不做处理，原样返回</p>
     *
     * @param statementId
     * @param param
     * @return
     */
    public List queryWithPermission(String statementId, Object param) {
        return queryWithSqlHandler(statementId, param, new SqlHandler() {
            @Override
            public String handle(String sql, Object[] params) {
                return getSqlWithPermission(sql);
            }
        });
    }
    /**
     * 附带权限过滤的查询指定需要过滤的表
     *
     * <p>为SQL添加权限过滤（通过RID字段过滤），如果当前用户为admin时，不做处理，原样返回</p>
     *
     * @param statementId
     * @param param
     * @return
     */
    public List queryWithPermissionAssignTable(String statementId, Object param,final String TableName) {
        return queryWithSqlHandler(statementId, param, new SqlHandler() {
            @Override
            public String handle(String sql, Object[] params) {
                return getSqlWithPermissionAssignTable(sql,TableName);
            }
        });
    }

    /**
     * 分页方法
     *
     * @param statementId
     * @param param
     * @param pageForm
     * @return
     */
    public IPage findPage(String statementId, Object param, PageForm pageForm) {
        return findPage(statementId, param, pageForm, false);
    }

    /**
     * 分页方法
     *
     * @param statementId
     * @param param
     * @param pageForm
     * @return
     */
    public IPage findPage(String statementId, PageForm pageForm) {
        return findPage(statementId, "", pageForm, false);
    }

    /**
     * 带权限过滤的分页方法
     *
     * <p>为SQL添加权限过滤（通过UNIT_ID字段过滤），如果当前用户为admin时，不做处理，原样返回</p>
     *
     * @param statementId
     * @param param
     * @param pageForm
     * @return
     */
    public IPage findPageWithPermission(String statementId, Object param, PageForm pageForm) {
        return findPage(statementId, param, pageForm, true);
    }

    /**
     * 带权限过滤的分页方法
     *
     * <p>为SQL添加权限过滤（通过UNIT_ID字段过滤），如果当前用户为admin时，不做处理，原样返回</p>
     *
     * @param statementId
     * @param param
     * @param pageForm
     * @return
     */
    public IPage findPageWithPermission(String statementId, PageForm pageForm) {
        return findPage(statementId, "", pageForm, true);
    }

    /**
     * 分页方法
     *
     * @param statementId
     * @param param
     * @param pageForm
     * @param isPermissionNeeded 是否需要分页
     * @return
     */
    private IPage findPage(String statementId, Object param, final PageForm pageForm, final boolean isPermissionNeeded) {
        final int[] total = new int[1];
        List list = queryWithSqlHandler(statementId, param, new SqlHandler() {
            @Override
            public String handle(String sql, Object[] params) {
                if (isPermissionNeeded) {
                    sql = getSqlWithPermission(sql);//添加权限
                }
                //查询总记录数
                total[0] = jdbcTemplate.queryForInt("select count(1) as RECORDS from (" + sql + ") a ", params);
                return getSqlWithPagerLimit(sql, pageForm);
            }
        });
        return new Page(list, total[0], pageForm.getPageSize(), pageForm.getPage());
    }
    

    /**
     * 为SQL添加权限过滤（通过UNIT_ID字段过滤），如果当前用户为admin时，不做处理，原样返回
     * 监控版本
     * @param sql
     * @return
     */
   /* private String getSqlWithPermission(final String sql) {
        final String userId = currentUser.getUserId();
        String newSql = sql;
        if (!"admin".equals(userId)) {//非admin用户进行权限过滤
            log.debug("当前用户为普通用户，进行权限过滤！");
            newSql = new StringBuilder("select t.* "
                    + " from (").append(sql).append(") t,"
                    + "      (select U.UNIT_ID from TB_SYS_ROLE_UNITID U, T_SYS_USER_ROLE R "
                    + "        where U.ROLE_ID = R.ROLE_ID and R.USER_ID = '").append(userId).append("') r "
                    + " where (t.UNIT_ID = r.UNIT_ID or t.UNIT_ID like r.UNIT_ID||'-%' or t.UNIT_ID like r.UNIT_ID||':%')").toString();
            log.debug("附加权限后SQL: " + newSql);
        } else {
            log.debug("当前用户为admin，不进行权限过滤！");
        }
        return newSql;
    }
    */
    
    
    /**
     * 
     */
    private String getSqlWithPermission(final String sql) {
        final String userId = currentUser.getUSER_ID();
        String newSql = sql;
      
        if (!"admin".equals(userId)) {//非admin用户进行权限过滤
            log.debug("当前用户为普通用户，进行权限过滤！");
            newSql=new StringBuilder("select t.* from(").append(sql).append(")T,(SELECT V.* FROM V_ASSET_ALL V, (SELECT RR.RES_CATEGORY_ID FROM TB_SYS_ROLE_RES RR,T_SYS_USER_ROLE UR WHERE RR.ROLE_ID=UR.ROLE_ID AND UR.USER_ID='").append(userId).append("')R "+
                                     " WHERE V.rid=R.RES_CATEGORY_ID "+
                                     " OR    V.category_id LIKE R.RES_CATEGORY_ID||'%') USER_RES WHERE T.RID=USER_RES.RID" 
                                     ).toString();
            log.debug("附加权限后SQL: " + newSql);
        } else {
            log.debug("当前用户为admin，不进行权限过滤！");
        }
        return newSql;
    }
    private String  getSqlWithPermissionAssignTable(final String sql, String tableName)
    {
    	String newSql=sql;
    	final String userId = currentUser.getUSER_ID();
    	String FilterSql=new StringBuilder("(select t.* from "+tableName+" T,(SELECT V.* FROM V_ASSET_ALL V, (SELECT RR.RES_CATEGORY_ID FROM TB_SYS_ROLE_RES RR,T_SYS_USER_ROLE UR WHERE RR.ROLE_ID=UR.ROLE_ID AND UR.USER_ID='").append(userId).append("')R "+
                " WHERE V.rid=R.RES_CATEGORY_ID "+
                " OR    V.category_id LIKE R.RES_CATEGORY_ID||'%') USER_RES WHERE T.RID=USER_ID.RID)" ).toString();
                ;
    	if(sql.toUpperCase().indexOf(tableName.toUpperCase())!=-1)
    	{
    		newSql.toUpperCase().replaceAll(tableName.toUpperCase(), FilterSql);
    	}
    	return newSql;
    }
   
    
    /**
     * 为SQL添加分页包装
     *
     * @param sql
     * @param pageForm
     * @return
     */
    private String getSqlWithPagerLimit(final String sql, final PageForm pageForm) {
        final int start = pageForm.getPage() * pageForm.getPageSize();
        final int end = (pageForm.getPage() + 1) * pageForm.getPageSize();
        final String sidx = pageForm.getSidx();
        final String sord = pageForm.getSord();
        final StringBuilder _sql = new StringBuilder().append(sql);
        //排序
        if (StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(sord)) {
            _sql.insert(0, "select * from (").append(") T1 order by ").append(sidx).append(" ").append(sord);
        }
        //分页
        _sql.insert(0, "select * from (select row_.*  from (");
        _sql.append(") row_ limit ").append(start).append(",").append(pageForm.getPageSize()).append(") T2 ");
        log.debug("分页： " + _sql);
        return _sql.toString();
    }

    /**
     * 提供查询前对sql处理的功能
     *
     * @param statementId
     * @param param
     * @param sqlHandler sql处理器
     * @return
     */
    protected List queryWithSqlHandler(final String statementId, final Object param, final SqlHandler sqlHandler) {
        if (sqlHandler != null) {
            final MappedStatement mappedStatement = sqlMapClient.getMappedStatement(statementId);
            final Sql dySql = mappedStatement.getSql();
            if (Proxy.isProxyClass(dySql.getClass())) {
                log.debug("该Sql对象已经是代理对象，设置新的sql处理器。");
                ((SqlProxyHandler) Proxy.getInvocationHandler(dySql)).setSqlHandler(sqlHandler);
            } else {
                log.debug("创建Sql的代理对象！");
                final SqlProxyHandler sqlProxyHandler = new SqlProxyHandler(dySql, sqlHandler);
                final Class sqlClass = dySql.getClass();
                final Sql proxy = (Sql) Proxy.newProxyInstance(sqlClass.getClassLoader(), sqlClass.getInterfaces(), sqlProxyHandler);
                mappedStatement.setSql(proxy);
            }
        }
        try {
            return sqlMapClient.queryForList(statementId, param);
        } catch (SQLException ex) {
            throw new RuntimeException("查询失败", ex);
        }
    }

    protected IPage findPageWithSqlHandler(String statementId, Object param, final PageForm pageForm, final SqlHandler sqlHandler) {
        final int[] total = new int[1];
        List list = queryWithSqlHandler(statementId, param, new SqlHandler() {
            @Override
            public String handle(String sql, Object[] params) throws Throwable {
                String nsql = sqlHandler.handle(sql, params);
                //查询总记录数
                total[0] = jdbcTemplate.queryForInt("select count(1) as RECORDS from (" + nsql + ")", params);
                return getSqlWithPagerLimit(nsql, pageForm);
            }
        });
        return new Page(list, total[0], pageForm.getPageSize(), pageForm.getPage());
    }

    private static final class SqlProxyHandler implements InvocationHandler {

        private final Sql sql;
        private final ThreadLocal<SqlHandler> sqlHandler = new ThreadLocal();

        public SqlProxyHandler(Sql sql, SqlHandler handler) {
            this.sql = sql;
            setSqlHandler(handler);
        }

        public Sql getSql() {
            return sql;
        }

        public void setSqlHandler(SqlHandler handler) {
            this.sqlHandler.set(handler);
        }

        public SqlHandler getSqlHandler() {
            return sqlHandler.get();
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(getSql(), args);
            if ("getSql".equals(method.getName()) && getSqlHandler() != null) {
                log.debug("原SQL： " + result);
                final StatementScope statementScope = (StatementScope) args[0];
                final Object[] params = statementScope.getParameterMap().getParameterObjectValues(statementScope, args[1]);
                result = getSqlHandler().handle((String) result, params);
                log.debug("处理后： " + result);
                setSqlHandler(null);//执行完成后清除线程局部变量，下次调用需要设置新值，否则不拦截getSql方法
            }
            return result;
        }
    }

    protected static interface SqlHandler {

        /**
         * 处理sql语句
         *
         * @param sql ibatis生成的sql语句，其中参数用?号占位
         * @param params sql对应的参数
         * @return
         * @throws Throwable
         */
        String handle(String sql, Object[] params) throws Throwable;
    }
}
